/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xui_lib.component.shadow;

import static com.xuexiang.xui_lib.component.shadow.ShadowButton.LABEL;

import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.BlurDrawLooper;
import ohos.agp.render.Canvas;
import ohos.agp.render.LinearShader;
import ohos.agp.render.Paint;
import ohos.agp.render.Shader;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;

import java.util.Arrays;

/**
 * ShadowDrawable
 *
 * @since 2021-04-21
 */
public class ShadowDrawable {
    /**
     * DEFAULT_SHADOW_COLOR
     */
    public static final Color DEFAULT_SHADOW_COLOR = new Color(Color.getIntColor("#4d000000"));

    /**
     * 方形
     */
    public static final int SHAPE_RECTANGLE = 0;
    /**
     * 圆形
     */
    public static final int SHAPE_ROUND = 1;

    private static final int DIVISOR = 2;

    private static final int DEFAULT_VP = 8;

    /**
     * 阴影圆角弧度
     */
    private int mShadowRadius;
    /**
     * 形状: SHAPE_RECTANGLE OR SHAPE_ROUND
     */
    private int mShape;
    /**
     * 圆角弧度
     */
    private int mShapeRadius;
    /**
     * X轴阴影偏移
     */
    private int mOffsetX;
    /**
     * Y轴阴影偏移
     */
    private int mOffsetY;
    /**
     * 背景颜色[大于1为渐变色]
     */
    private Color[] mBgColor;
    private RectFloat mRect;
    private Paint mShadowPaint;
    private Paint mBgPaint;

    private int componentWidth;
    private int componetHeight;

    private ShadowDrawable(int shape, Color[] bgColor, int shapeRadius,
                           Color shadowColor, int shadowRadius, int offsetX, int offsetY) {
        mShape = shape;
        HiLog.info(LABEL, "onDrawLog bgColor:" + bgColor.length);
        mBgColor = bgColor;
        mShapeRadius = shapeRadius;
        mShadowRadius = shadowRadius;
        mOffsetX = offsetX;
        mOffsetY = offsetY;

        mShadowPaint = new Paint();
        mShadowPaint.setColor(Color.WHITE);
        mShadowPaint.setAntiAlias(true);
        mShadowPaint.setBlurDrawLooper(new BlurDrawLooper(shadowRadius, offsetX, offsetY, shadowColor));
        mBgPaint = new Paint();
        mBgPaint.setAntiAlias(true);
    }

    /**
     * ViewParams
     *
     * @since 2019-04-20
     */
    public static class ViewParams {
        private int paddingLeft;
        private int paddingTop;
        private Color textColor;
        private int textSize;
        private String text;

        /**
         * setPaddingLeft
         *
         * @param paddingLeft
         * @return ViewParams
         */
        public ViewParams setPaddingLeft(int paddingLeft) {
            this.paddingLeft = paddingLeft;
            return this;
        }

        /**
         * setPaddingTop
         *
         * @param paddingTop
         * @return ShadowDrawable
         */
        public ViewParams setPaddingTop(int paddingTop) {
            this.paddingTop = paddingTop;
            return this;
        }

        /**
         * setTextColor
         *
         * @param textColor
         * @return ShadowDrawable
         */
        public ViewParams setTextColor(Color textColor) {
            this.textColor = textColor;
            return this;
        }

        /**
         * setTextSize
         *
         * @param textSize
         * @return ShadowDrawable
         */
        public ViewParams setTextSize(int textSize) {
            this.textSize = textSize;
            return this;
        }

        /**
         * setText
         *
         * @param text
         * @return ShadowDrawable
         */
        public ViewParams setText(String text) {
            this.text = text;
            return this;
        }

        public int getPaddingLeft() {
            return paddingLeft;
        }

        public int getPaddingTop() {
            return paddingTop;
        }

        public Color getTextColor() {
            return textColor;
        }

        public int getTextSize() {
            return textSize;
        }

        public String getText() {
            return text;
        }
    }

    /**
     * onDraw
     *
     * @param canvas
     * @param viewParams
     * @return
     */
    public void onDraw(Canvas canvas, ViewParams viewParams) {
        mRect = new RectFloat(
            viewParams.getPaddingLeft() + mShadowRadius - mOffsetX,
            viewParams.getPaddingTop() + mShadowRadius - mOffsetY,
            componentWidth - mShadowRadius - mOffsetX,
            componetHeight - mShadowRadius - mOffsetY);
        HiLog.info(LABEL, "onDrawLog mShadowRadius:"
            + mShadowRadius + "     mOffsetX:" + mOffsetX
            + "    mOffsetY:" + mOffsetY);
        if (mBgColor != null) {
            if (mBgColor.length == 1) {
                mBgPaint.setColor(mBgColor[0]);
            } else {
                Color[] mColors = new Color[mBgColor.length];
                for (int temp = 0; temp < mColors.length; temp++) {
                    mColors[temp] = mBgColor[temp];
                }
                LinearShader mShader = new LinearShader(
                    new Point[]{new Point(mRect.left, mRect.getHeight() / DIVISOR),
                        new Point(mRect.right, mRect.getHeight() / DIVISOR)},
                    new float[]{},
                    mColors,
                    Shader.TileMode.CLAMP_TILEMODE);
                mBgPaint.setShader(mShader, Paint.ShaderType.LINEAR_SHADER);
            }
        }
        HiLog.info(LABEL, mShape + ":" + mShape);
        if (mShape == SHAPE_RECTANGLE) {
            canvas.drawRoundRect(mRect, mShapeRadius, mShapeRadius, mShadowPaint);
            canvas.drawRoundRect(mRect, mShapeRadius, mShapeRadius, mBgPaint);
        } else {
            canvas.drawCircle(mRect.getCenter().getPointX(),
                mRect.getCenter().getPointY(),
                Math.min(mRect.getWidth(),
                    mRect.getHeight()) / DIVISOR, mShadowPaint);
            canvas.drawCircle(mRect.getCenter().getPointX(),
                mRect.getCenter().getPointY(),
                Math.min(mRect.getWidth(), mRect.getHeight()) / DIVISOR, mBgPaint);
        }

        Paint mPaint = new Paint();
        mPaint.setColor(viewParams.getTextColor());
        mPaint.setTextSize(viewParams.getTextSize());
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);

        int mTextWidth = mPaint.getTextBounds(viewParams.getText()).getWidth();
        canvas.drawText(mPaint, viewParams.getText(),
            componentWidth / DIVISOR - mTextWidth / DIVISOR - mOffsetX,
            componetHeight / DIVISOR + mOffsetY / DIVISOR);
    }

    /**
     * 获取属性信息
     *
     * @param context
     * @param attrs
     * @return ShadowDrawable
     */
    public static ShadowDrawable fromAttributeSet(Context context, AttrSet attrs) {
        int shadowRadius = AttrHelper.vp2px(DEFAULT_VP, context);
        if (attrs.getAttr("sd_shadowRadius").isPresent()) {
            shadowRadius = attrs.getAttr("sd_shadowRadius").get().getIntegerValue();
        }
        Color shadowColor = DEFAULT_SHADOW_COLOR;
        if (attrs.getAttr("sd_shadowColor").isPresent()) {
            shadowColor = attrs.getAttr("sd_shadowColor").get().getColorValue();
        }
        int shape = SHAPE_RECTANGLE;
        if (attrs.getAttr("sd_shapeType").isPresent()) {
            String value = attrs.getAttr("sd_shapeType").get().getStringValue();
            if ("round".equals(value)) {
                shape = SHAPE_ROUND;
            }
        }

        int offsetX = 0;
        if (attrs.getAttr("sd_offsetX").isPresent()) {
            offsetX = attrs.getAttr("sd_offsetX").get().getIntegerValue();
        }
        int offsetY = 0;
        if (attrs.getAttr("sd_offsetY").isPresent()) {
            offsetY = attrs.getAttr("sd_offsetY").get().getIntegerValue();
        }
        Color bgColor = Color.WHITE;
        if (attrs.getAttr("sd_bgColor").isPresent()) {
            bgColor = attrs.getAttr("sd_bgColor").get().getColorValue();
        }
        Color secondBgColor = null;
        if (attrs.getAttr("sd_secondBgColor").isPresent()) {
            secondBgColor = attrs.getAttr("sd_secondBgColor").get().getColorValue();
        }
        int shapeRadius = AttrHelper.vp2px(DEFAULT_VP, context);
        Builder builder = new Builder()
            .setShape(shape)
            .setShapeRadius(shapeRadius)
            .setShadowColor(shadowColor)
            .setShadowRadius(shadowRadius)
            .setOffsetX(offsetX)
            .setOffsetY(offsetY);

        if (secondBgColor != null) {
            builder.setBgColor(new Color[]{bgColor, secondBgColor});
        } else {
            builder.setBgColor(bgColor);
        }
        return builder.build();
    }

    /**
     * initEstimateSize
     *
     * @param widthEstimateConfig
     * @param heightEstimateConfig
     */
    public void initEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        componentWidth = Component.EstimateSpec.getSize(widthEstimateConfig);
        componetHeight = Component.EstimateSpec.getSize(heightEstimateConfig);
    }

    /**
     * Builder
     *
     * @since 2019-04-20
     */
    public static class Builder {
        private static final int DEFAULT_SHAPE_RADIUS = 10;
        private static final int DEFAULT_SHADOW_RADIUS = 16;
        private int mShape;
        private int mShapeRadius;
        private Color mShadowColor;
        private int mShadowRadius;
        private int mOffsetX = 0;
        private int mOffsetY = 0;
        private Color[] mBgColor;

        /**
         * Builder
         */
        public Builder() {
            mShape = SHAPE_RECTANGLE;
            mShapeRadius = DEFAULT_SHAPE_RADIUS;
            mShadowColor = DEFAULT_SHADOW_COLOR;
            mShadowRadius = DEFAULT_SHADOW_RADIUS;
            mOffsetX = 0;
            mOffsetY = 0;
            mBgColor = new Color[1];
            mBgColor[0] = Color.TRANSPARENT;
        }

        /**
         * setShape
         *
         * @param viewShape
         * @return Builder
         */
        public Builder setShape(int viewShape) {
            this.mShape = viewShape;
            return this;
        }

        /**
         * setShapeRadius
         *
         * @param shapeRadius
         * @return Builder
         */
        public Builder setShapeRadius(int shapeRadius) {
            this.mShapeRadius = shapeRadius;
            return this;
        }

        /**
         * setShadowColor
         *
         * @param shadowColor
         * @return Builder
         */
        public Builder setShadowColor(Color shadowColor) {
            this.mShadowColor = shadowColor;
            return this;
        }

        /**
         * setShadowRadius
         *
         * @param shadowRadius
         * @return Builder
         */
        public Builder setShadowRadius(int shadowRadius) {
            this.mShadowRadius = shadowRadius;
            return this;
        }

        /**
         * setOffsetX
         *
         * @param offsetX
         * @return Builder
         */
        public Builder setOffsetX(int offsetX) {
            this.mOffsetX = offsetX;
            return this;
        }

        /**
         * setOffsetY
         *
         * @param offsetY
         * @return Builder
         */
        public Builder setOffsetY(int offsetY) {
            this.mOffsetY = offsetY;
            return this;
        }

        /**
         * setBgColor
         *
         * @param bgColor
         * @return Builder
         */
        public Builder setBgColor(Color bgColor) {
            this.mBgColor[0] = bgColor;
            return this;
        }

        /**
         * setBgColor
         *
         * @param bgColor
         * @return Builder
         */
        public Builder setBgColor(Color[] bgColor) {
            this.mBgColor = Arrays.copyOf(bgColor,bgColor.length);
            return this;
        }

        /**
         * build
         *
         * @return ShadowDrawable
         */
        public ShadowDrawable build() {
            return new ShadowDrawable(mShape, mBgColor, mShapeRadius,
                mShadowColor, mShadowRadius, mOffsetX, mOffsetY);
        }
    }
}
